import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { In, Like, Repository } from 'typeorm';
import BaseMaterial from '@main/entities/service/admin/base/base-material.entity';
import { BaseCustomService } from '@main/service/modules/admin/base/custom/custom.service';
import { ApiException } from '@main/common/exceptions/api.exception';
import BaseMaterialMachineParameter from '@main/entities/service/admin/base/base-materia-machine-parameter.entity';
import BaseMaterialMachineParameterUnit from '@main/entities/service/admin/base/base-materia-machine-parameter-unit.entity';
import BasePlate from '@main/entities/service/admin/base/base-plate.entity';
import BaseColor from '@main/entities/service/admin/base/base-color.entity';
import { generateExcelFn } from '@main/excel';
import { SysOperationLogService } from '../../system/operationLog/operationLog.service';

@Injectable()
export class BaseMaterialService {
  constructor(
    @InjectRepository(BaseMaterial)
    private materialRepository: Repository<BaseMaterial>,
    private baseCustomService: BaseCustomService,
    @InjectRepository(BaseMaterialMachineParameter)
    private materialMachineParameterRepository: Repository<BaseMaterialMachineParameter>,
    @InjectRepository(BaseMaterialMachineParameterUnit)
    private materialMachineParameterUnitRepository: Repository<BaseMaterialMachineParameterUnit>,
    @InjectRepository(BasePlate)
    private plateRepository: Repository<BasePlate>,
    @InjectRepository(BaseColor)
    private colorRepository: Repository<BaseColor>,
    private operationLogService: SysOperationLogService
  ) {}

  async list() {
    return await this.materialRepository.find();
  }

  /**
   * 罗列所有配置
   */
  async page(data) {
    const { pageSize, pageNum, entity = {} } = data;

    const { materialName, materialCode, ids = [] } = entity;

    const where = {
      materialName: Like(`%${materialName}%`),
      materialCode: Like(`%${materialCode}%`),
    };

    if (ids && ids.length) {
      where['id'] = In(ids);
    }

    return await this.materialRepository.findAndCount({
      where,
      order: {
        updateTime: 'DESC',
      },
      take: pageSize,
      skip: (pageNum - 1) * pageSize,
    });
  }

  async export(dto, lang) {
    const [list] = await this.page(dto);

    if (!list || !(list as any).length) {
      throw new ApiException(10052);
    }

    const dataList = list;

    return await generateExcelFn(
      {
        sheetName: 'material',
        mainHeaderList: [
          {
            label: 'materialName',
          },
          {
            label: 'materialCode',
          },
          {
            label: 'version',
          },
          {
            label: 'remark',
          },
        ],
        dataList,
      },
      lang
    );
  }

  /**
   * 新增
   */
  async add(data, user, mac, ip, syncHostSqlite) {
    const databaseOperationLogList = [];
    const { customCode, customName, customShort } = data;

    if (customCode && customName && customShort) {
      const res = await this.baseCustomService.isExistCode(customCode);

      if (!res) {
        await this.baseCustomService.add(
          {
            customCode,
            customName,
            customShort,
            contacts: '',
            contactsTel: '',
            customTypeId: null,
            customTypeName: null,
            salesman: '',
            customHobby: '',
            customAddress: '',
            remark: '',
          },
          user,
          mac,
          ip,
          syncHostSqlite
        );
      }
    }

    const material = await this.materialRepository.insert({
      ...data,
      createName: user.nickName,
      createUserName: user.userName,
      updateName: user.nickName,
      updateUserName: user.userName,
    });
    databaseOperationLogList.push({
      type: 'add',
      dataType: 'obj',
      database: 'BaseMaterial',
      checkOnlyKeyList: [],
      data: material,
      whereObj: null,
      remark: `BaseMaterial表新增数据`,
    });
    await this.operationLogService.add(
      {
        type: 'add',
        msg: `产品资料管理模块新增产品资料`,
        databaseOperationLogList,
        remark: `新增产品资料${data.materialName}`,
        mac,
        ip,
        syncHostSqlite: isNaN(Number(syncHostSqlite)) ? 0 : Number(syncHostSqlite),
      },
      user
    );
  }

  /**
   * 删除
   */
  async delete(idList, user, mac, ip, syncHostSqlite) {
    const databaseOperationLogList = [];
    await this.materialRepository.delete(idList);
    databaseOperationLogList.push({
      type: 'delete',
      dataType: 'array',
      database: 'BaseMaterial',
      checkOnlyKeyList: [],
      data: null,
      whereObj: idList,
      remark: `BaseMaterial表删除产品资料`,
    });
    await this.operationLogService.add(
      {
        type: 'delete',
        msg: `产品资料管理模块删除产品资料`,
        databaseOperationLogList,
        remark: `删除产品资料`,
        mac,
        ip,
        syncHostSqlite: isNaN(Number(syncHostSqlite)) ? 0 : Number(syncHostSqlite),
      },
      user
    );
  }

  async isExistKey(data) {
    const { materialCode, version } = data;

    const result = await this.materialRepository.findOne({ where: { materialCode, version } });

    if (result) throw new ApiException(10025);
  }

  async getColumnsList() {
    const entityMetadata = this.materialRepository.metadata;

    const list = entityMetadata.columns.map((column) => {
      return {
        key: column.propertyName,
        comment: column.comment,
      };
    });

    return list;
  }

  async saveParameterByMaterialVersion(data, user, mac, ip, syncHostSqlite) {
    const databaseOperationLogList = [];
    // 保存产品下发参数
    const { machineCode, version, materialCode, list } = data;

    const obj = { machineCode, materialCode };

    if (version) {
      obj['version'] = version;
    }
    await this.materialMachineParameterRepository.delete(obj);
    databaseOperationLogList.push({
      type: 'delete',
      dataType: 'array',
      database: 'BaseMaterialMachineParameter',
      checkOnlyKeyList: [],
      data: null,
      whereObj: obj,
      remark: `BaseMaterialMachineParameter表删除产品下发参数`,
    });
    await this.operationLogService.add(
      {
        type: 'delete',
        msg: `删除产品下发参数`,
        databaseOperationLogList,
        remark: `删除产品下发参数`,
        mac,
        ip,
        syncHostSqlite: isNaN(Number(syncHostSqlite)) ? 0 : Number(syncHostSqlite),
      },
      user
    );
    const materialMachineParameter = await this.materialMachineParameterRepository.insert(list);
    databaseOperationLogList.push({
      type: 'add',
      dataType: 'obj',
      database: 'BaseMaterialMachineParameter',
      checkOnlyKeyList: [],
      data: materialMachineParameter,
      whereObj: null,
      remark: `BaseMaterialMachineParameter表新增产品下发参数`,
    });
    await this.operationLogService.add(
      {
        type: 'add',
        msg: `新增产品下发参数`,
        databaseOperationLogList,
        remark: `新增产品下发参数`,
        mac,
        ip,
        syncHostSqlite: isNaN(Number(syncHostSqlite)) ? 0 : Number(syncHostSqlite),
      },
      user
    );
  }

  async getParameterUnitByMaterialVersion(data) {
    const { machineCode, version, materialCode } = data;

    const obj = { machineCode, materialCode };

    if (version) {
      obj['version'] = version;
    }

    return await this.materialMachineParameterUnitRepository.find({
      where: obj,
      order: {
        printUnit: 'ASC',
      },
    });
  }

  async saveParameterUnitByMaterialVersion(data, user, mac, ip, syncHostSqlite) {
    const databaseOperationLogList = [];
    // 印刷单元参数保存
    const { machineCode, version, materialCode, list } = data;

    const obj = { machineCode, materialCode };

    if (version) {
      obj['version'] = version;
    }
    await this.materialMachineParameterUnitRepository.delete(obj);
    databaseOperationLogList.push({
      type: 'delete',
      dataType: 'array',
      database: 'BaseMaterialMachineParameterUnit',
      checkOnlyKeyList: [],
      data: null,
      whereObj: obj,
      remark: `BaseMaterialMachineParameterUnit表删除印刷单元参数`,
    });
    await this.operationLogService.add(
      {
        type: 'delete',
        msg: `删除印刷单元参数`,
        databaseOperationLogList,
        remark: `删除印刷单元参数`,
        mac,
        ip,
        syncHostSqlite: isNaN(Number(syncHostSqlite)) ? 0 : Number(syncHostSqlite),
      },
      user
    );

    for (let i = 0; i < list.length; i++) {
      const { plateCode, plateName, plateId, color, colorName, colorId, colorModel } = list[i];

      if (plateCode && plateName) {
        const plate = await this.plateRepository.save({ id: plateId, plateCode, plateName });
        databaseOperationLogList.push({
          type: 'add',
          dataType: 'obj',
          database: 'BasePlate',
          checkOnlyKeyList: [],
          data: plate,
          whereObj: null,
          remark: `BasePlate表新增印刷单元参数印版`,
        });
        await this.operationLogService.add(
          {
            type: 'add',
            msg: `新增印刷单元参数印版`,
            databaseOperationLogList,
            remark: `新增印刷单元参数印版`,
            mac,
            ip,
            syncHostSqlite: isNaN(Number(syncHostSqlite)) ? 0 : Number(syncHostSqlite),
          },
          user
        );
      }

      if (colorId) {
        const color1 = await this.colorRepository.save({
          id: colorId,
          colorName,
          colorModel,
          color,
        });
        databaseOperationLogList.push({
          type: 'add',
          dataType: 'obj',
          database: 'BaseColor',
          checkOnlyKeyList: [],
          data: color1,
          whereObj: null,
          remark: `BaseColor表新增印刷单元参数水墨`,
        });
        await this.operationLogService.add(
          {
            type: 'add',
            msg: `新增印刷单元参数水墨`,
            databaseOperationLogList,
            remark: `新增印刷单元参数水墨`,
            mac,
            ip,
            syncHostSqlite: isNaN(Number(syncHostSqlite)) ? 0 : Number(syncHostSqlite),
          },
          user
        );
      }
    }
    const materialMachineParameterUnit = await this.materialMachineParameterUnitRepository.insert(
      list
    );
    databaseOperationLogList.push({
      type: 'add',
      dataType: 'obj',
      database: 'BaseMaterialMachineParameterUnit',
      checkOnlyKeyList: [],
      data: materialMachineParameterUnit,
      whereObj: null,
      remark: `BaseMaterialMachineParameterUnit表新增印刷单元参数`,
    });
    await this.operationLogService.add(
      {
        type: 'add',
        msg: `新增印刷单元参数`,
        databaseOperationLogList,
        remark: `新增印刷单元参数`,
        mac,
        ip,
        syncHostSqlite: isNaN(Number(syncHostSqlite)) ? 0 : Number(syncHostSqlite),
      },
      user
    );
  }

  async getParameterByMaterialVersion(data) {
    const { machineCode, version, materialCode } = data;

    const obj = { machineCode, materialCode };

    if (version) {
      obj['version'] = version;
    }

    return await this.materialMachineParameterRepository.find({ where: obj });
  }
}
